#include <stdio.h>
#include <string.h>

#include "CurlHttpClient.hpp"

/* HTTP命令传输层控制 */
#define HTTPBASE_CMD_TIMEOUT               (6)
#define HTTPBASE_CMD_VERBOSE               (0)

volatile bool CurlHttpClient::m_globalInitFlag = false;

#define FALSE (0)
/**
 * @fn     CurlHttpClient::globalInit
 * @brief    当多个线程，同时进行curl_easy_init时，由于会调用非线程安全的curl_global_init，因此导致崩溃。
 *         应该在主线程优先调用curl_global_init进行全局初始化。再在线程中使用curl_easy_init。
 * @param[in]
 * @retval CURLE_OK ：成功，others：失败
 */
int CurlHttpClient::globalInit()
{
    CURLcode ret = CURLE_OK;

    if(false == m_globalInitFlag)
    {
        /**
         *   See https://curl.se/libcurl/c/curl_global_init.html
         *
         *   This function must be called at least once within a program (a program is all the code that shares a memory space)
         * before the program calls any other function in libcurl. The environment it sets up is constant for the life of the program
         * and is the same for every program, so multiple calls have the same effect as one call.
         *
         *   The flags option is a bit pattern that tells libcurl exactly what features to init, as described below. Set the desired
         * bits by ORing the values together. In normal operation, you must specify CURL_GLOBAL_ALL. Don't use any other value unless
         * you are familiar with it and mean to control internal operations of libcurl.
         *
         *   This function is not thread safe. You must not call it when any other thread in the program (i.e. a thread sharing the same memory)
         * is running. This doesn't just mean no other thread that is using libcurl. Because curl_global_init calls functions of other libraries
         * that are similarly thread unsafe, it could conflict with any other thread that uses these other libraries.
         */
        ret = curl_global_init(CURL_GLOBAL_ALL);
        if(CURLE_OK == ret)
        {
            m_globalInitFlag = true;
        }
    }

    return ret;
}

static int OnDebug(CURL *, curl_infotype itype, char * pData, size_t size, void *)
{
    if(itype == CURLINFO_TEXT)
    {
        //printf("[TEXT]%s\n", pData);
    }
    else if(itype == CURLINFO_HEADER_IN)
    {
        printf("[HEADER_IN]%s\n", pData);
    }
    else if(itype == CURLINFO_HEADER_OUT)
    {
        printf("[HEADER_OUT]%s\n", pData);
    }
    else if(itype == CURLINFO_DATA_IN)
    {
        printf("[DATA_IN]%s\n", pData);
    }
    else if(itype == CURLINFO_DATA_OUT)
    {
        printf("[DATA_OUT]%s\n", pData);
    }
    return 0;
}

static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
    std::string* str = dynamic_cast<std::string*>((std::string *)lpVoid);
    if( NULL == str || NULL == buffer )
    {
        return -1;
    }

    char* pData = (char*)buffer;
    str->append(pData, size * nmemb);
    return size * nmemb;
}
#if 0
/* 函数未使用，暂使用编译宏注销 */
static size_t OnReadData(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
    std::string* str = dynamic_cast<std::string*>((std::string *)lpVoid);
    if( NULL == str || NULL == buffer )
    {
        return -1;
    }

    memcpy(buffer, str->c_str(), str->length());
    return str->length();
}
#endif

static size_t headerCallback(char *buffer, size_t size, size_t nitems, void *userdata)
{
    /* http head also do this callback, drop those without ':' */
    bool findFlag = false;
    unsigned int i = 0;

    for(; i< nitems; i++)
    {
        if(buffer[i] == ':')
        {
            findFlag = true;
            break;
        }
    }
    if(!findFlag)
    {
        return nitems * size;
    }

    std::string key = std::string(buffer, i);

    /* find value begin */
    for(i++; i < nitems; i++)
    {
        if(buffer[i] != ' ')
        {
            break;
        }
    }

    /* find value end */
    unsigned int j = nitems-1;
    for(; j > i; j--)
    {
        if((buffer[j] != '\r') && (buffer[j] != '\n'))
        {
            break;
        }
    }

    /* value can be null */
    std::string value;
    if(j > i)
    {
        value = std::string(buffer+i, j-i+1);
    }

    CurlHttpClient::HttpKeyVal item = {key, value};
    std::list<CurlHttpClient::HttpKeyVal> *p = static_cast< std::list<CurlHttpClient::HttpKeyVal> *>(userdata);
    p->push_back(item);

    return nitems * size;
}

CurlHttpClient::CurlHttpClient(int format):
m_bDebug(false)
,m_timeout(HTTPBASE_CMD_TIMEOUT)
,m_verbose(HTTPBASE_CMD_VERBOSE)
,m_headers(NULL)
{
    std::string head = "Content-Type:application/json";
    AddHeader(head);

    /**
     * 当多个线程，同时进行curl_easy_init时，由于会调用非线程安全的curl_global_init，因此导致崩溃。
     * 应该在主线程优先调用curl_global_init进行全局初始化。再在线程中使用curl_easy_init
     */
    globalInit();
}

CurlHttpClient::CurlHttpClient(std::string user, std::string pwd):
m_bDebug(false)
,m_timeout(HTTPBASE_CMD_TIMEOUT)
,m_verbose(HTTPBASE_CMD_VERBOSE)
,m_headers(NULL)
{
    m_httpAuthMod = (unsigned long)(CURLAUTH_BASIC | CURLAUTH_DIGEST);
    m_username = user;
    m_password = pwd;

    std::string head = "Content-Type:application/json";
    AddHeader(head);

    /**
     * 当多个线程，同时进行curl_easy_init时，由于会调用非线程安全的curl_global_init，因此导致崩溃。
     * 应该在主线程优先调用curl_global_init进行全局初始化。再在线程中使用curl_easy_init
     */
    globalInit();
}

CurlHttpClient::~CurlHttpClient(void)
{
    ClearHeaders();
}

void CurlHttpClient::SetTimeout(int timeout)
{
    m_timeout = timeout;
}

void CurlHttpClient::AddHeader(std::string & headText)
{
    if(headText.length() > 0)
        m_headers = curl_slist_append(m_headers, headText.c_str());
}

void CurlHttpClient::ClearHeaders()
{
    if(m_headers)
    {
        curl_slist_free_all(m_headers);
        m_headers = NULL;
    }
}

void CurlHttpClient::setAuthMode(unsigned long authMap)
{
    m_httpAuthMod |= authMap;
}

/**
 *  检测鉴权模式
 *  若当前鉴权模式完全包含入参authMap中的鉴权模式
 *  则返回 0， 否侧返回 -1
 */
int CurlHttpClient::checkAuthMode(unsigned long authMap)
{
    if( (m_httpAuthMod&authMap) == authMap)
        return 0;
    return -1;
}

int CurlHttpClient::Post(const std::string & strUrl, long & httpCode, const std::string & strPost, std::string & strResponse)
{
    CURLcode res;
    CURL* curl = curl_easy_init();
    if(NULL == curl)
    {
        return CURLE_FAILED_INIT;
    }

    if(m_bDebug)
    {
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
        curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
    }

    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, FALSE);

    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, m_timeout);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, m_timeout);

    /**
     *  添加basic 和 digest鉴权方式
     */
    curl_easy_setopt(curl, CURLOPT_USERNAME, m_username.c_str());
    curl_easy_setopt(curl, CURLOPT_PASSWORD, m_password.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, m_httpAuthMod);

    curl_easy_setopt(curl, CURLOPT_HEADER, 0); //将响应头信息和相应体一起传给OnWriteData
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_headers);

    curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); //url地址

    curl_easy_setopt(curl, CURLOPT_POST, 1); //设置问非0表示本次操作为post
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str()); //post参数

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); //对返回的数据进行操作的函数地址
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); //这是write_data的第四个参数值
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
    curl_easy_setopt(curl, CURLOPT_READDATA, NULL);

    /** 
    * 当多个线程都使用超时处理的时候，同时主线程中有sleep或是wait等操作。
    * 如果不设置这个选项，libcurl将会发信号打断这个wait从而导致程序退出。
    */
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

    curl_easy_setopt(curl, CURLOPT_VERBOSE, m_verbose); //打印调试信息
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //设置为非0,响应头信息location

    res = curl_easy_perform(curl);

    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);

    curl_easy_cleanup(curl);

    return res;
}

int CurlHttpClient::Get(const std::string & strUrl, long & httpCode, const std::string & strGet, std::string & strResponse)
{
    CURLcode res;
    CURL* curl = curl_easy_init();
    if(NULL == curl)
    {
        return CURLE_FAILED_INIT;
    }

    if(m_bDebug)
    {
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
        curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
    }
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, FALSE);

    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, m_timeout);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, m_timeout);

    /**
     *  添加basic 和 digest鉴权方式
     */
    curl_easy_setopt(curl, CURLOPT_USERNAME, m_username.c_str());
    curl_easy_setopt(curl, CURLOPT_PASSWORD, m_password.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, m_httpAuthMod);

    curl_easy_setopt(curl, CURLOPT_HEADER, 0); //将响应头信息和相应体一起传给write_data
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_headers);

    curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); //url地址

    curl_easy_setopt(curl, CURLOPT_POST, 0); //设置问非0表示本次操作为post
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ""); //post参数
    curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); //对返回的数据进行操作的函数地址
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); //这是write_data的第四个参数值
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
    curl_easy_setopt(curl, CURLOPT_READDATA, NULL);

    /** 
    * 当多个线程都使用超时处理的时候，同时主线程中有sleep或是wait等操作。
    * 如果不设置这个选项，libcurl将会发信号打断这个wait从而导致程序退出。
    */
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

    curl_easy_setopt(curl, CURLOPT_VERBOSE, m_verbose); //打印调试信息
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //设置为非0,响应头信息location

    res = curl_easy_perform(curl);

    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);

    curl_easy_cleanup(curl);

    return res;
}

 int CurlHttpClient::Get(const std::string & strUrl, long & httpCode, const std::string & strGet, std::string & strResponse, std::list<HttpKeyVal> & resHeaders)
{
    CURLcode res;
    CURL* curl = curl_easy_init();
    if(NULL == curl)
    {
        return CURLE_FAILED_INIT;
    }

    if(m_bDebug)
    {
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
        curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
    }
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, FALSE);

    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, m_timeout);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, m_timeout);

    /**
     *  添加basic 和 digest鉴权方式
     */
    curl_easy_setopt(curl, CURLOPT_USERNAME, m_username.c_str());
    curl_easy_setopt(curl, CURLOPT_PASSWORD, m_password.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, m_httpAuthMod);

    curl_easy_setopt(curl, CURLOPT_HEADER, 0); //将响应头信息和相应体一起传给write_data
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_headers);

    curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); //url地址

    curl_easy_setopt(curl, CURLOPT_POST, 0); //设置问非0表示本次操作为post
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ""); //post参数
    curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); //对返回的数据进行操作的函数地址
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); //这是write_data的第四个参数值

    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headerCallback);
    curl_easy_setopt(curl, CURLOPT_HEADERDATA, &resHeaders);

    curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
    curl_easy_setopt(curl, CURLOPT_READDATA, NULL);

    /** 
    * 当多个线程都使用超时处理的时候，同时主线程中有sleep或是wait等操作。
    * 如果不设置这个选项，libcurl将会发信号打断这个wait从而导致程序退出。
    */
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

    curl_easy_setopt(curl, CURLOPT_VERBOSE, m_verbose); //打印调试信息
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //设置为非0,响应头信息location

    res = curl_easy_perform(curl);

    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);

    curl_easy_cleanup(curl);

    return res;
}

int CurlHttpClient::Put(const std::string & strUrl, long & httpCode, const std::string & strPut, std::string & strResponse)
{
    CURLcode res;
    CURL* curl = curl_easy_init();
    if(NULL == curl)
    {
        return CURLE_FAILED_INIT;
    }

    if(m_bDebug)
    {
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
        curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
    }

    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, FALSE);

    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, m_timeout);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, m_timeout);

    /**
     *  添加basic 和 digest鉴权方式
     */
    curl_easy_setopt(curl, CURLOPT_USERNAME, m_username.c_str());
    curl_easy_setopt(curl, CURLOPT_PASSWORD, m_password.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, m_httpAuthMod);

    curl_easy_setopt(curl, CURLOPT_HEADER, 0); //将响应头信息和相应体一起传给write_data
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_headers);

    curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); //url地址

    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPut.c_str()); //post参数

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); //对返回的数据进行操作的函数地址
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); //这是write_data的第四个参数值
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
    curl_easy_setopt(curl, CURLOPT_READDATA, NULL);

    /** 
    * 当多个线程都使用超时处理的时候，同时主线程中有sleep或是wait等操作。
    * 如果不设置这个选项，libcurl将会发信号打断这个wait从而导致程序退出。
    */
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

    curl_easy_setopt(curl, CURLOPT_VERBOSE, m_verbose); //打印调试信息
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //设置为非0,响应头信息location

    res = curl_easy_perform(curl);

    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);

    curl_easy_cleanup(curl);

    return res;
}

int CurlHttpClient::Download(const std::string & strUrl, long & httpCode, const std::string & strGet, WriteDataCBFunc cbWriteDataFunc, void *lpVoid)
{
    CURLcode res;
    CURL* curl = curl_easy_init();
    if(NULL == curl || NULL == cbWriteDataFunc)
    {
        return CURLE_FAILED_INIT;
    }

    if(m_bDebug)
    {
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
        curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
    }

    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, m_timeout);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, m_timeout);

    /**
     *  添加basic 和 digest鉴权方式
     */
    curl_easy_setopt(curl, CURLOPT_USERNAME, m_username.c_str());
    curl_easy_setopt(curl, CURLOPT_PASSWORD, m_password.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, m_httpAuthMod);

    curl_easy_setopt(curl, CURLOPT_HEADER, 0); //将响应头信息和相应体一起传给write_data
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_headers);

    curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); //url地址

    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strGet.c_str()); //post参数

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cbWriteDataFunc); //对返回的数据进行操作的函数地址
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, lpVoid); //这是write_data的第四个参数值
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
    curl_easy_setopt(curl, CURLOPT_READDATA, NULL);

    /** 
    * 当多个线程都使用超时处理的时候，同时主线程中有sleep或是wait等操作。
    * 如果不设置这个选项，libcurl将会发信号打断这个wait从而导致程序退出。
    */
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

    curl_easy_setopt(curl, CURLOPT_VERBOSE, m_verbose); //打印调试信息
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //设置为非0,响应头信息location

    res = curl_easy_perform(curl);

    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);

    curl_easy_cleanup(curl);

    return res;
}



int CurlHttpClient::Posts(const std::string & strUrl, long & httpCode, const std::string & strPost, std::string & strResponse, const char * pCaPath)
{
    CURLcode res;
    CURL* curl = curl_easy_init();
    if(NULL == curl)
    {
        return CURLE_FAILED_INIT;
    }

    if(m_bDebug)
    {
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
        curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);  
    }

    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, m_timeout);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, m_timeout);

    /**
     *  添加basic 和 digest鉴权方式
     */
    curl_easy_setopt(curl, CURLOPT_USERNAME, m_username.c_str());
    curl_easy_setopt(curl, CURLOPT_PASSWORD, m_password.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, m_httpAuthMod);

    curl_easy_setopt(curl, CURLOPT_HEADER, 0); //将响应头信息和相应体一起传给write_data
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_headers);

    curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());

    curl_easy_setopt(curl, CURLOPT_POST, 1);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); //对返回的数据进行操作的函数地址
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); //这是write_data的第四个参数值
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
    curl_easy_setopt(curl, CURLOPT_READDATA, NULL);

    /** 
    * 当多个线程都使用超时处理的时候，同时主线程中有sleep或是wait等操作。
    * 如果不设置这个选项，libcurl将会发信号打断这个wait从而导致程序退出。
    */
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

    if(NULL == pCaPath)
    {
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
    }
    else
    {
    //缺省情况就是PEM，所以无需设置，另外支持DER
    //curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM");
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);//todogjf
    curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
    }

    curl_easy_setopt(curl, CURLOPT_VERBOSE, m_verbose); //打印调试信息
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //设置为非0,响应头信息location

    res = curl_easy_perform(curl);

    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);

    curl_easy_cleanup(curl);

    return res;
}

int CurlHttpClient::Gets(const std::string & strUrl, long & httpCode, std::string & strResponse, const char * pCaPath)
{
    CURLcode res;
    CURL* curl = curl_easy_init();
    if(NULL == curl)
    {
        return CURLE_FAILED_INIT;
    }

    if(m_bDebug)
    {
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
        curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
    }

    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, m_timeout);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, m_timeout);

    /**
     *  添加basic 和 digest鉴权方式
     */
    curl_easy_setopt(curl, CURLOPT_USERNAME, m_username.c_str());
    curl_easy_setopt(curl, CURLOPT_PASSWORD, m_password.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, m_httpAuthMod);

    curl_easy_setopt(curl, CURLOPT_HEADER, 0); //将响应头信息和相应体一起传给write_data
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_headers);

    curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());

    curl_easy_setopt(curl, CURLOPT_POST, 0); //设置问非0表示本次操作为post
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ""); //post参数
    curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); //对返回的数据进行操作的函数地址
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); //这是write_data的第四个参数值
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
    curl_easy_setopt(curl, CURLOPT_READDATA, NULL);

    /** 
    * 当多个线程都使用超时处理的时候，同时主线程中有sleep或是wait等操作。
    * 如果不设置这个选项，libcurl将会发信号打断这个wait从而导致程序退出。
    */
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

    if(NULL == pCaPath)
    {
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
    }
    else
    {
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);//todogjf
    curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
    }

    curl_easy_setopt(curl, CURLOPT_VERBOSE, m_verbose); //打印调试信息
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //设置为非0,响应头信息location

    res = curl_easy_perform(curl);

    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);

    curl_easy_cleanup(curl);

    return res;
}

int CurlHttpClient::Delete(const std::string & strUrl, long & httpCode, const std::string & strDelete, std::string & strResponse)
{
    CURLcode res;
    CURL* curl = curl_easy_init();
    if(NULL == curl)
    {
        return CURLE_FAILED_INIT;
    }

    if(m_bDebug)
    {
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
        curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
    }

    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, m_timeout);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, m_timeout);

    /**
     *  添加basic 和 digest鉴权方式
     */
    curl_easy_setopt(curl, CURLOPT_USERNAME, m_username.c_str());
    curl_easy_setopt(curl, CURLOPT_PASSWORD, m_password.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, m_httpAuthMod);

    curl_easy_setopt(curl, CURLOPT_HEADER, 0); //将响应头信息和相应体一起传给write_data
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_headers);

    curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); //url地址

    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strDelete.c_str()); //post参数

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); //对返回的数据进行操作的函数地址
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); //这是write_data的第四个参数值
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
    curl_easy_setopt(curl, CURLOPT_READDATA, NULL);

    /** 
    * 当多个线程都使用超时处理的时候，同时主线程中有sleep或是wait等操作。
    * 如果不设置这个选项，libcurl将会发信号打断这个wait从而导致程序退出。
    */
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

    curl_easy_setopt(curl, CURLOPT_VERBOSE, m_verbose); //打印调试信息
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //设置为非0,响应头信息location

    res = curl_easy_perform(curl);

    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);

    curl_easy_cleanup(curl);

    return res;
}

void CurlHttpClient::SetDebug(bool bDebug)
{
    m_bDebug = bDebug;
}

